// Mesh Resource
// (c) jimon game studio

#ifndef JEH_JEMESHRESOURCE
#define JEH_JEMESHRESOURCE

#include "IResourceManager.h"
#include "jeSharedResource.h"
#include "jeMeshResource.h"
#include "IMeshLoader.h"
#include "jeMeshTools.h"

namespace je
{
	namespace media
	{
		//! Mesh Resource
		class jeMeshResource:public je::media::IResource
		{
		public:
			typedef jeSharedResourceManagerUniversal jeSharedMeshResourceManager;
		protected:
			core::IBuffer * MeshBuffer;
			jeSharedMeshResourceManager * SharedManager;
			u1 CreateTBN;
		public:
			//! Constructor
			jeMeshResource(const jeStringc & ResourceName)
				:IResource(ResourceName),MeshBuffer(NULL)
			{
				JENEW(SharedManager,jeSharedMeshResourceManager)
			}

			//! Destructor
			~jeMeshResource()
			{
				JEDELETE(SharedManager)
			}

			//! Get Shared Manager
			jeSharedMeshResourceManager * GetSharedManager()
			{
				return SharedManager;
			}

			//! Get Mesh Buffer
			core::IBuffer * GetMeshBuffer()
			{
				return MeshBuffer;
			}

			//! Need To Create TBN
			u1 NeedToCreateTBN()
			{
				return CreateTBN;
			}

			//! Load Resource
			void Load()
			{
				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query(jeStringc("SELECT * FROM MeshResources WHERE Name = '")+CurrentResourceName+jeStringc("'"));
				MeshBuffer = Query->GetFieldBuffer("Data");
				CreateTBN = Query->GetFieldu1("CreateTBN");
				Query->Drop();
			}

			//! UnLoad Resource
			void UnLoad()
			{
				MeshBuffer->Drop();
				MeshBuffer = NULL;
			}

			//! Get Type Name
			virtual jeStringc GetTypeName()
			{
				return jeStringc("MeshResource");
			}
		};

		//! Mesh Resource Factory
		class jeMeshResourceFactory:public je::media::IResourceFactory
		{
		protected:
			typedef jeMap<jeStringc,jeMeshResource*> MeshMapType;
			MeshMapType MeshMap;
		public:
			//! Constructor
			jeMeshResourceFactory()
			{
			}

			//! Destructor
			~jeMeshResourceFactory()
			{
				ClearResources();
			}

			//! Add Resources
			void AddResources(IResource * Resource)
			{
				MeshMap.set(Resource->GetName(),static_cast<jeMeshResource*>(Resource));
				Resource->Grab();
			}

			//! Load Resources
			void LoadResources()
			{
				ClearResources();

				core::IDataBase_Query * Query = GetResourceManager()->GetDataBase()->Query("SELECT * FROM MeshResources");
				while(!Query->Eof())
				{
					jeStringc ResourceName = Query->GetFieldjeStringc("Name");
					jeMeshResource * MeshResource = NULL;
					JENEW(MeshResource,jeMeshResource(ResourceName))
					MeshMap.set(ResourceName,MeshResource);
					Query->NextRow();
				}
				Query->Drop();
			}

			//! Clear Resources
			void ClearResources()
			{
				for(MeshMapType::Iterator Iter = MeshMap.getIterator();!Iter.atEnd();Iter++)
					Iter->getValue()->Drop();
				MeshMap.clear();
			}

			//! Return Resource
			IResource * GetResource(const jeStringc & ResourceName)
			{
				MeshMapType::Node * Node = MeshMap.find(ResourceName);
				if(Node)
					return Node->getValue();
				else
					return NULL;
			}

			//! Return Resource Type
			jeStringc GetResourceType()
			{
				return jeStringc("MeshResource");
			}

			//! Garbage Collector
			void GarbageCollector()
			{
				for(MeshMapType::Iterator Iter = MeshMap.getIterator();!Iter.atEnd();Iter++)
					if(Iter->getValue()->IsNeedToUnload())
						Iter->getValue()->GarbageUnload();
			}
		};

		//! Shared Mesh
		class jeSharedMesh:public media::ISharedResource
		{
		protected:
			jeStringc MeshResourceName;
			video::IRender * CurrentRender;
			scene::jeMesh * Mesh;

		public:
			//! Constructor
			jeSharedMesh(jeMeshResource * MeshResource,video::IRender * Render)
				:CurrentRender(Render)
			{
				MeshResource->AddUsage();
				MeshResourceName = MeshResource->GetName();
				Mesh = scene::GetMeshLoader()->LoadMesh(MeshResource->GetMeshBuffer(),CurrentRender);

				if(MeshResource->NeedToCreateTBN())
					CreateTangentSpaceMesh(Mesh);

				MeshResource->RemoveUsage();
			}

			//! Destructor
			~jeSharedMesh()
			{
				Mesh->Drop();
			}

			//! Get Mesh
			scene::jeMesh * GetMesh()
			{
				return Mesh;
			}

			//! Get Resource Name
			const jeStringc & GetResourceName()
			{
				return MeshResourceName;
			}
		};
	}
}

#define JE_MESHRESOURCE( __Name ) JE_RESOURCEBASE_GET(__Name,MeshResource)

#define JE_MESHRESOURCE_GRAB( __Var, __Res, __Key, __Render ) JE_RESOURCEBASE_SHARED_GRAB(__Var,__Res,__Key,__Render,Mesh)
#define JE_MESHRESOURCE_DROP( __Var, __Key, __Render) JE_RESOURCEBASE_SHARED_DROP(__Var,__Key,MeshResource)

#define JE_MESHRESOURCE_SHARED_GRAB( __Var, __Res, __Render ) JE_MESHRESOURCE_GRAB(__Var,__Res,__Render->GetContext(),__Render)
#define JE_MESHRESOURCE_SHARED_DROP( __Var, __Render) JE_MESHRESOURCE_DROP(__Var,__Render->GetContext(),__Render)

#endif
